using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using System.Security.Cryptography;

namespace PictureMimic
{
	public class CandidateDNA
	{
		public uint Identity;
		public uint PaternalIdentity;
		public uint MaternalIdentity;

		public uint Generation;

		public ulong Fitness;

		public CandidateGene[] DominantSequence;
		public CandidateGene[] PaternalSequence;
		public CandidateGene[] MaternalSequence;

		public CandidateDNA(uint identity, uint generation)
		{
			Identity = identity;
			PaternalIdentity = 0;
			MaternalIdentity = 0;

			Generation = generation;

			Fitness = 0;

			DominantSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];
			PaternalSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];
			MaternalSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];

			// No Parents? No Problems, we will just randomly create you!

			byte[] seed;
			RNGCryptoServiceProvider seeder;
			Random randomiser;

			seed = new byte[32];
			seeder = new RNGCryptoServiceProvider();
			seeder.GetBytes(seed);

			randomiser = new Random((int)BitConverter.ToInt32(seed, 0));

			for (int i = 0; i < EvolutionaryConstraints.MaxPolygons; i++)
			{
				PaternalSequence[i] = new CandidateGene();
				MaternalSequence[i] = new CandidateGene();

				if (randomiser.Next(0, 2) < 1)
				{
					DominantSequence[i] = PaternalSequence[i];
				}
				else
				{
					DominantSequence[i] = MaternalSequence[i];
				}
			}
		}

		public CandidateDNA(uint identity, uint generation, CandidateDNA paternalDNA, CandidateDNA maternalDNA)
		{
			Identity = identity;
			PaternalIdentity = paternalDNA.Identity;
			MaternalIdentity = maternalDNA.Identity;
			Generation = generation;

			Fitness = 0;

			DominantSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];
			PaternalSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];
			MaternalSequence = new CandidateGene[EvolutionaryConstraints.MaxPolygons];

			bool inbred = (paternalDNA.PaternalIdentity == maternalDNA.PaternalIdentity ||
						   paternalDNA.MaternalIdentity == maternalDNA.MaternalIdentity);

			// Congratulations! It's a polygon! It takes after its...

			byte[] seed;
			RNGCryptoServiceProvider seeder;
			Random randomiser;

			seed = new byte[32];
			seeder = new RNGCryptoServiceProvider();
			seeder.GetBytes(seed);

			randomiser = new Random((int)BitConverter.ToInt32(seed, 0));

			for (int i = 0; i < EvolutionaryConstraints.MaxPolygons; i++)
			{
				if (randomiser.Next(0, 2) < 1)
				{
					PaternalSequence[i] = new CandidateGene(paternalDNA.PaternalSequence[i], inbred);
				}
				else
				{
					PaternalSequence[i] = new CandidateGene(paternalDNA.MaternalSequence[i], inbred);
				}

				if (randomiser.Next(0, 2) < 1)
				{
					MaternalSequence[i] = new CandidateGene(maternalDNA.MaternalSequence[i], inbred);
				}
				else
				{
					MaternalSequence[i] = new CandidateGene(maternalDNA.PaternalSequence[i], inbred);
				}

				DominantSequence[i] = EvolutionaryConstraints.DominanceModel.GetDominant(PaternalSequence[i], MaternalSequence[i], paternalDNA, maternalDNA);
			}
		}

		public Bitmap GetBitmap()
		{
			Bitmap bitmap = new Bitmap(EvolutionaryConstraints.EnvironmentWidth, EvolutionaryConstraints.EnvironmentHeight);
			Graphics graphics = Graphics.FromImage(bitmap);
			Pen pen = new Pen(Color.Black);
			Brush brush = pen.Brush;

			graphics.FillRectangle(brush, 0, 0, EvolutionaryConstraints.EnvironmentWidth, EvolutionaryConstraints.EnvironmentHeight);

			foreach (CandidateGene gene in DominantSequence)
			{
				pen = new Pen(gene.Colour);
				brush = pen.Brush;

				graphics.FillPolygon(brush, gene.Points);
			}

			return bitmap;
		}

		public void EvaluateFitness(Bitmap target)
		{
			Fitness = EvolutionaryConstraints.FitnessModel.CalculateFitness(this, target);
		}
	}
}
